Django での並列性とデータベース接続
最終更新日 2024年11月29日(金)
Table of Contents
Gunicorn などのマルチプロセス Web サーバーを使用して並列性を向上させる場合は、アプリがデータベースに対して保持する接続の数や、データベースが受け付けることができる接続の数に注意する必要があります。各プロセスには、データベースへの異なる接続が必要です。これに対応するために、同時に複数の接続を保持できる接続プールを提供するためのツールがいくつか存在します。
永続的な接続
デフォルトでは、Django は、アプリケーションのリクエストサイクルごとにのみ新しい永続的なデータベース接続を作成します。これは、Django が SQL クエリを使用してデータベースにアクセスしようとしたときに常に実行されます。
新しい接続を常に開いておくことは高コストの操作であり、Django の永続的な接続を使用することによって緩和される場合があります。
永続的な接続を有効にすることは簡単です。settings.py
内の接続設定で CONN_MAX_AGE
を設定します。
DATABASES = {
'default': {
...
'CONN_MAX_AGE': 600
dj-database-url モジュールを使用している場合は、次の設定をお勧めします。
import dj_database_url
DATABASES['default'] = dj_database_url.config(conn_max_age=600, ssl_require=True)
設定されると、すべてが想定どおりに動作します。
データベース接続の最大数
Heroku では、マネージド Postgres データベースが提供されます。階層型データベースごとにさまざまな接続制限があります。Essential 層データベースは 20 個および 40 個の接続に制限されています。本番プランのデータベース (プラン「Standard 0」以上) の制限数はそれ以上です。データベースは、アクティブな接続の最大数に達すると、新しい接続を受け付けなくなります。これにより、アプリケーションが接続タイムアウトになり、例外が発生する可能性があります。
スケールアウトするときは、アプリケーションに必要なアクティブな接続の数に注意することが重要です。各 dyno で 5 つのデータベース接続が許可されている場合は、より堅牢なデータベースのプロビジョニングが必要になるまでに、4 つの dyno にしかスケールアウトできません。
これで、接続プールを設定する方法や、データベースで処理できる接続の数を見つける方法がわかったので、各 dyno に必要な接続の適切な数を計算する必要があります。
必要な接続数の計算
アプリケーションコードでスレッドを手動で作成していない場合は、Web サーバーの設定を使用して、必要な接続の数を導き出すことができます。Gunicorn Web サーバーは、複数のプロセスを使用してスケールアウトします。アプリケーションで新しいスレッドを開いていない場合は、各プロセスが 1 つの接続を受け取ります。たとえば、次のように 3 つのワーカープロセスを使用するように Gunicorn を設定するとします。
$ heroku config:set WEB_CONCURRENCY=3
これにより、アプリはワーカーに 3 つの接続を使用します。つまり、各 dyno には 3 つの接続が必要になります。たとえば、essential-0
または essential-1
プランを使用している場合は、6 つの dyno にスケールアウトできます。これは、アクティブなデータベース接続の数が最大 20 個のうちの 18 個になることを示します。ただし、一部の接続が不適切な状態または不明な状態になる可能性があります。このため、アプリケーションの pool
を 1
または 2
のどちらかに設定して、ゾンビ接続がデータベースを飽和させないようにすることをお勧めします。後述の「不適切な接続」のセクションを参照してください。
WEB_CONCURRENCY
環境変数は、プロセスの dyno サイズに基づいて、Heroku によって自動的に設定されます。この機能は、アプリケーションのための適切な開始点になることを目的にしています。プロセスのメモリ要件を把握し、それに応じてこの環境設定を調整することをお勧めします。
スループット最大化のための Python アプリケーションのチューニングについての詳細は、「Python アプリケーションの並列性の最適化」を参照してください。
アクティブな接続の数
本番環境では、データベースをチェックすることにより、アプリケーションによって取得される接続の数を確認できます。
$ heroku pg:psql
これにより、開発データベースへの接続が開かれます。その後、次を実行して Postgres データベースへの接続の数を確認できます。
select count(*) from pg_stat_activity where pid <> pg_backend_pid() and usename = current_user;
これにより、そのデータベース上の接続の数が返されます。
count
-------
5
(1 row)
接続は低速で開かれるため、localhost
にある実行中のアプリケーションを、カウントが増えなくなるまで複数回ヒットする必要があります。開発セットアップでは、アプリによる新しい接続の作成に必要な負荷を生成できない可能性があるため、正確なカウントを得るには、そのデータベースクエリを本番データベースの内部で実行します。
PgBouncer を使用した接続の制限
データベース接続の制限に達するまで、追加の dyno を使用して引き続きアプリケーションをスケールアウトできます。この段階に達する前に、データベースクライアントか PgBouncer を使用して接続プールを有効にして、各 dyno に必要な接続の数を制限することをお勧めします。
データベースクライアントを使用
一部のデータベースクライアントでは接続プールをサポートしています。Django で psycopg
パッケージを使用する場合は、データベース接続プール設定を有効にしてください。それ以外の場合は、psycopg 接続プールのドキュメントを参照してください。
PgBouncer を使用
PgBouncer はアプリとデータベース間のプロキシとして機能し、アプリクライアント間でデータベースサーバー接続を共有します。
詳細については、次を参照してください。